package com.tianji.promotion.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domian.vo.LearningLessonVO;
import com.tianji.promotion.domain.dto.CouponFormDTO;
import com.tianji.promotion.domain.dto.CouponIssueFormDTO;
import com.tianji.promotion.domain.query.CouponQuery;
import com.tianji.promotion.domain.vo.CouponDetailVO;
import com.tianji.promotion.domain.vo.CouponPageVO;
import com.tianji.promotion.domain.vo.CouponScopeVO;
import com.tianji.promotion.domain.vo.CouponVO;
import com.tianji.promotion.entity.Coupon;
import com.tianji.promotion.entity.CouponScope;
import com.tianji.promotion.entity.UserCoupon;
import com.tianji.promotion.enums.CouponStatus;
import com.tianji.promotion.enums.ObtainType;
import com.tianji.promotion.enums.UserCouponStatus;
import com.tianji.promotion.mapper.CouponMapper;
import com.tianji.promotion.mapper.CouponScopeMapper;
import com.tianji.promotion.service.ICouponScopeService;
import com.tianji.promotion.service.ICouponService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.promotion.service.IUserCouponService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 优惠券的规则信息 服务实现类
 * </p>
 *
 * @author author
 * @since 2024-03-28
 */
@Service
@RequiredArgsConstructor
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements ICouponService {

    private final ICouponScopeService ScopeService;

    private final CouponScopeMapper scopeMapper;

    private final IUserCouponService userCouponService;

    @Override
    @Transactional
    public void saveCoupon(CouponFormDTO couponDTO) {
        //1.封装优惠券对象
        Coupon coupon = BeanUtils.copyBean(couponDTO, Coupon.class);
        //2.保存优惠券
        save(coupon);
        //2.1.判断是否限定使用范围
        if (!couponDTO.getSpecific()){
            return;
        }
        Long id = coupon.getId();
        //3.检验优惠券范围
        List<Long> scopes = couponDTO.getScopes();
        if (CollUtils.isEmpty(scopes)){
            throw new BadRequestException("优惠券范围不能为空");
        }

        //4.转换po
        List<CouponScope> collect = scopes.stream()
                .map(bizId -> new CouponScope().setBizId(bizId).setCouponId(id))
                .collect(Collectors.toList());

        //5.保存优惠券范围
        ScopeService.saveBatch(collect);

    }

    @Override
    public PageDTO<CouponPageVO> queryCouponPage(CouponQuery query) {
        //1.分页查询优惠券
        Page<Coupon> page = lambdaQuery()
                .eq(query.getStatus() != null, Coupon::getStatus, query.getStatus())
                .eq(query.getType() != null, Coupon::getType, query.getType())
                .like(query.getName() != null, Coupon::getName, query.getName())
                .page(query.toMpPageDefaultSortByCreateTimeDesc());

        //2.封装vo
        List<Coupon> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            return PageDTO.empty(page);
        }
        List<CouponPageVO> list = BeanUtils.copyList(records, CouponPageVO.class);
        //3.返回
        return PageDTO.of(page, list);
    }

    @Override
    @Transactional
    public void beginIssue(CouponIssueFormDTO couponDTO) {
        //1.查询优惠券
        Coupon coupon = getById(couponDTO.getId());
        if (coupon == null){
            throw new BizIllegalException("优惠券不存在");
        }
        //2.校验优惠券状态
        if (coupon.getStatus()!= CouponStatus.DRAFT && coupon.getStatus()!= CouponStatus.PAUSE){
            throw new BizIllegalException("优惠券状态异常");
        }
        //3.判断是否立刻发放
        LocalDateTime issueBeginTime = couponDTO.getIssueBeginTime();
        LocalDateTime now = LocalDateTime.now();
        boolean isBegin = issueBeginTime == null || !issueBeginTime.isAfter(now);

        // 4.拷贝属性到PO
        Coupon c = BeanUtils.copyBean(couponDTO, Coupon.class);

        //5.更新状态
        if (isBegin){
            c.setStatus(CouponStatus.ISSUING);
            c.setIssueBeginTime(now);
        }else {
            c.setStatus(CouponStatus.UN_ISSUE);
        }
        //6.更新到数据库
        updateById(c);


    }

    @Override
    @Transactional
    public void updateCoupon(CouponFormDTO couponDTO) {
        //1.封装优惠券对象
        Coupon coupon = BeanUtils.copyBean(couponDTO, Coupon.class);
        //2.保存优惠券
        updateById(coupon);
        //2.1.判断是否限定使用范围
        if (!couponDTO.getSpecific()){
            return;
        }
        Long id = coupon.getId();
        //3.检验优惠券范围
        List<Long> scopes = couponDTO.getScopes();
        if (CollUtils.isEmpty(scopes)){
            throw new BadRequestException("优惠券范围不能为空");
        }

        //4.转换po
        List<CouponScope> collect = scopes.stream()
                .map(bizId -> new CouponScope().setBizId(bizId).setCouponId(id))
                .collect(Collectors.toList());

        //5.保存优惠券范围
        ScopeService.updateBatchById(collect);

    }

    @Override
    public void removeCoupon(Long id) {
        removeById(id);
    }


    @Override
    public CouponDetailVO findById(Long id) {
        //1.查询优惠券
        Coupon coupon = getById(id);

        //2.封装vo
        CouponDetailVO vo = BeanUtils.copyBean(coupon, CouponDetailVO.class);
        //3.1.查询优惠券范围
        List<CouponScope> scopes = ScopeService.lambdaQuery()
                    .eq(CouponScope::getCouponId,id)
                    .list();

        if (scopes.size() == 0){
            scopes = ScopeService.lambdaQuery()
                    .eq(CouponScope::getType, 1)
                    .list();
        }


        //3.1.2.根据bizId查询CourseName课程信息
        // TODO 待查
//        List<Long> bizIds = scopes.stream().map(CouponScope::getBizId).collect(Collectors.toList());

        //3.1.1.查询分类
        List<CouponScopeVO> categoryScopes = scopes.stream()
                    .map(scope -> new CouponScopeVO().setId(scope.getBizId()).setName("学习"))
                    .collect(Collectors.toList());
        //3.2.封装vo
        List<CouponScopeVO> list = BeanUtils.copyList(categoryScopes, CouponScopeVO.class);

        vo.setScopes(list);

        //3.返回
        return vo;
    }

    @Override
    public List<CouponVO> queryIssuingCoupons() {
        // 1.查询发放中的优惠券列表
        List<Coupon> coupons = lambdaQuery()
                .eq(Coupon::getStatus, CouponStatus.ISSUING)
                .eq(Coupon::getObtainWay, ObtainType.PUBLIC)
                .list();

        if (CollUtils.isEmpty(coupons)){
            return CollUtils.emptyList();
        }
        //2.统计当前用户已经领取的优惠卷的信息
        List<Long> couponIds = coupons.stream().map(Coupon::getId).collect(Collectors.toList());

        //2.1.查询当前用户已经领取优惠卷的数据
        List<UserCoupon> userCoupons = userCouponService.lambdaQuery()
                .in(UserCoupon::getCouponId, couponIds)
                .eq(UserCoupon::getUserId, UserContext.getUser())
                .list();

        //2.2.统计当前用户对优惠券的已经领取数量
        Map<Long, Long> issuedMap  = userCoupons.stream()
                .collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));

        // 2.3.统计当前用户对优惠券的已经领取并且未使用的数量
        Map<Long, Long> unusedMap  = userCoupons.stream()
                .filter(uc -> uc.getStatus() == UserCouponStatus.USED)
                .collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));

        // 3.封装VO结果
        List<CouponVO> list = new ArrayList<>(coupons.size());

        for (Coupon c : coupons) {
            // 3.1.拷贝PO属性到VO
            CouponVO vo = BeanUtils.copyBean(c, CouponVO.class);
            list.add(vo);

            // 3.2.是否可以领取：已经被领取的数量 < 优惠券总数量 && 当前用户已经领取的数量 < 每人限领数量
            vo.setAvailable( c.getIssueNum() < c.getTotalNum() &&
                    issuedMap.getOrDefault(c.getId(), 0L) < c.getUserLimit());
            // 3.3.是否可以使用：当前用户已经领取并且未使用的优惠券数量 > 0
            vo.setReceived(unusedMap.getOrDefault(c.getId(),  0L) > 0);
        }

        return list;
    }


}
